﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

using MASAS.MSM.DataLayer.DataMapper;
using MASAS.MSM.DomainLayer.Feed;
using MASAS.MSM.DomainLayer.Logging;
using MASAS.MSM.DomainLayer.Model;

namespace MASAS.MSM.DomainLayer
{

    /// <summary>
    /// MASAS message handler.
    /// </summary>
    public class MessageHandler : IDisposable
    {

        // Private members...
        private bool        disposed    = false;
        private FeedPoller  feedPoller  = null;
        private IDataStore  dataStore   = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="MessageHandler"/> class.
        /// </summary>
        /// <param name="feedPoller">The feed poller.</param>
        /// <param name="dataStore">The data store.</param>
        public MessageHandler( FeedPoller feedPoller, IDataStore dataStore )
        {
            this.feedPoller = feedPoller;
            this.dataStore = dataStore;

            feedPoller.OnNewEntriesAvailable += new Feed.EntriesAvailableEvent( feedPoller_OnNewEntriesAvailable );
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose( true );
            GC.SuppressFinalize( this );
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose( bool disposing )
        {
            if( !disposed )
            {
                if( disposing )
                {
                    // Free other state (managed objects).
                    feedPoller.OnNewEntriesAvailable -= new Feed.EntriesAvailableEvent( feedPoller_OnNewEntriesAvailable );
                }

                // Free your own state (unmanaged objects).
                // Set large fields to null.

                disposed = true;
            }
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="MessageHandler"/> is reclaimed by garbage collection.
        /// </summary>
        ~MessageHandler()
        {
            // Simply call Dispose(false).
            Dispose( false );
        }

        /// <summary>
        /// New entries available.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="hub">The hub.</param>
        /// <param name="entries">The entries.</param>
        private void feedPoller_OnNewEntriesAvailable( object sender, Hub hub, List<HubEntry> entries )
        {
            Logger.AddLogEntry( "Processing entries from Hub: " + hub.Name + " (" + hub.URI + ")." );

            dataStore.CurrentHub = hub;

            // Update the entries...
            foreach( HubEntry entry in entries )
            {
                ProcessTypedMessage( hub, entry );
            }

            // Update the Hub information...
            ProcessHubData( hub );

            Logger.AddLogEntry( string.Format( "{0} entries have been added to SharePoint site ({1}).", entries.Count, hub.URI ) );
        }

        /// <summary>
        /// Processes the typed message.
        /// </summary>
        /// <param name="entry">The entry.</param>
        private void ProcessTypedMessage( Hub hub, HubEntry entry )
        {
            // now we need to store the item.
            if( dataStore.EntryExistsByExternalID( entry.ExternalIdentifier ) )
            {
                if( !dataStore.UpdateEntry( entry ) )
                {
                    Logger.AddLogEntry( "ERROR: Entry could not be updated!" );
                }
            }
            else
            {
                if( !dataStore.AddEntry( entry ) )
                {
                    Logger.AddLogEntry( "ERROR: Entry could not be added!" );
                }
            }
        }

        /// <summary>
        /// Processes the hub data.
        /// </summary>
        /// <param name="hub">The hub.</param>
        private void ProcessHubData( Hub hub )
        {
            if( !dataStore.UpdateHubData( hub ) )
            {
                Logger.AddLogEntry( "ERROR: Hub data could not be updated!" );
            }
        }

    }

}